import 'dart:io' show Platform;

import 'package:flutter/foundation.dart' show kDebugMode, kIsWeb;
import 'package:flutter/material.dart';
import 'package:window_example/util/window_util.dart';
import 'package:window_manager/window_manager.dart';

import './mouse_state_builder.dart';
import '../icons/icons.dart';

typedef WindowButtonIconBuilder = Widget Function(
    WindowButtonContext buttonContext);
typedef WindowButtonBuilder = Widget Function(
    WindowButtonContext buttonContext, Widget icon);
typedef VoidCallback = void Function();

class WindowButtonContext {
  BuildContext context;
  MouseState mouseState;
  Color? backgroundColor;
  Color iconColor;
  Widget? iconImage;

  WindowButtonContext(
      {required this.context,
      required this.mouseState,
      this.backgroundColor,
      this.iconImage,
      required this.iconColor});
}

class WindowButtonColors {
  late Color normal;
  late Color mouseOver;
  late Color mouseDown;
  late Color iconNormal;
  late Color iconMouseOver;
  late Color iconMouseDown;

  WindowButtonColors(
      {Color? normal,
      Color? mouseOver,
      Color? mouseDown,
      Color? iconNormal,
      Color? iconMouseOver,
      Color? iconMouseDown}) {
    this.normal = normal ?? _defaultButtonColors.normal;
    this.mouseOver = mouseOver ?? _defaultButtonColors.mouseOver;
    this.mouseDown = mouseDown ?? _defaultButtonColors.mouseDown;
    this.iconNormal = iconNormal ?? _defaultButtonColors.iconNormal;
    this.iconMouseOver = iconMouseOver ?? _defaultButtonColors.iconMouseOver;
    this.iconMouseDown = iconMouseDown ?? _defaultButtonColors.iconMouseDown;
  }
}

/// 仅支持Windows平台
class WindowButtonIcons {
  final Widget normalIcon;
  final Widget mouseOverIcon;
  final Widget mouseDownIcon;

  WindowButtonIcons(this.normalIcon, this.mouseDownIcon, this.mouseOverIcon);
}

final _defaultButtonColors = WindowButtonColors(
    normal: Colors.transparent,
    iconNormal: const Color(0xFF805306),
    mouseOver: const Color(0xFF404040),
    mouseDown: const Color(0xFF202020),
    iconMouseOver: const Color(0xFFFFFFFF),
    iconMouseDown: const Color(0xFFF0F0F0));

class WindowButton extends StatelessWidget {
  final WindowButtonIconBuilder? iconBuilder;
  late final WindowButtonColors colors;
  final bool animate;
  final EdgeInsets? padding;
  final VoidCallback? onPressed;
  final Size? iconSize;
  final Size? backgroundSize;
  final WindowButtonIcons? icons;

  WindowButton(
      {Key? key,
      WindowButtonColors? colors,
      @required this.iconBuilder,
      this.padding,
      this.onPressed,
      this.iconSize,
      this.backgroundSize,
      this.icons,
      required this.animate})
      : super(key: key) {
    this.colors = colors ?? _defaultButtonColors;
  }

  Color getBackgroundColor(MouseState mouseState) {
    if (mouseState.isMouseDown) return colors.mouseDown;
    if (mouseState.isMouseOver) return colors.mouseOver;
    return colors.normal;
  }

  Color getIconColor(MouseState mouseState) {
    if (mouseState.isMouseDown) return colors.iconMouseDown;
    if (mouseState.isMouseOver) return colors.iconMouseOver;
    return colors.iconNormal;
  }

  Widget? getIconImage(MouseState mouseState) {
    if (mouseState.isMouseDown) return icons?.mouseDownIcon;
    if (mouseState.isMouseOver) return icons?.mouseOverIcon;
    return icons?.normalIcon;
  }

  @override
  Widget build(BuildContext context) {
    print("WindowButton:build$this");
    if (kIsWeb) {
      return Container();
    } else {
      // Don't show button on macOS
      if (Platform.isMacOS) {
        return Container();
      }
    }
    if (kDebugMode) {
      print("titleBarButtonSize:${WindowUtil().titleBarButtonSize}");
    }
    var mBackgroundSize = backgroundSize ?? WindowUtil().titleBarButtonSize;

    return MouseStateBuilder(
      builder: (context, mouseState) {
        if (kDebugMode) {
          print("mouseState:$mouseState");
        }
        WindowButtonContext buttonContext = WindowButtonContext(
            mouseState: mouseState,
            context: context,
            backgroundColor: getBackgroundColor(mouseState),
            iconColor: getIconColor(mouseState),
            iconImage: getIconImage(mouseState));

        var icon =
            (iconBuilder != null) ? iconBuilder!(buttonContext) : Container();

        var mIconSize = iconSize ??
            Size(mBackgroundSize.height / 3, mBackgroundSize.height / 3);
        if (kDebugMode) {
          print("mIconSize:$mIconSize");
        }
        // Used when buttonContext.backgroundColor is null, allowing the AnimatedContainer to fade-out smoothly.
        var fadeOutColor =
            getBackgroundColor(MouseState()..isMouseOver = true).withOpacity(0);
        var animationMs =
            mouseState.isMouseOver ? (animate ? 100 : 0) : (animate ? 200 : 0);

        var button = AnimatedContainer(
            curve: Curves.easeOut,
            duration: Duration(milliseconds: animationMs),
            color: buttonContext.backgroundColor ?? fadeOutColor,
            child: Align(
                alignment: Alignment.center,
                child: SizedBox.fromSize(
                  size: mIconSize,
                  child: icon,
                )));
        if (kDebugMode) {
          print("mBackgroundSize:$mBackgroundSize");
        }
        return SizedBox(
            width: mBackgroundSize.width,
            height: mBackgroundSize.height,
            child: (buttonContext.iconImage != null)
                ? Align(
                    alignment: Alignment.center,
                    child: buttonContext.iconImage,
                  )
                : button);
      },
      onPressed: () {
        if (onPressed != null) onPressed!();
      },
    );
  }
}

class MinimizeWindowButton extends WindowButton {
  MinimizeWindowButton(
      {Key? key,
      WindowButtonColors? colors,
      VoidCallback? onPressed,
      WindowButtonIcons? icons,
      Size? backgroundSize,
      Size? iconSize,
      bool? animate})
      : super(
            key: key,
            colors: colors,
            iconSize: iconSize,
            backgroundSize: backgroundSize,
            icons: icons,
            animate: animate ?? false,
            iconBuilder: (buttonContext) => MinimizeIcon(
                  color: buttonContext.iconColor,
                ),
            onPressed: onPressed ?? () => windowManager.minimize());
}

class MaximizeWindowButton extends WindowButton {
  MaximizeWindowButton(
      {Key? key,
      WindowButtonColors? colors,
      VoidCallback? onPressed,
      Size? backgroundSize,
      Size? iconSize,
      WindowButtonIcons? icons,
      bool? animate})
      : super(
            key: key,
            colors: colors,
            animate: animate ?? false,
            backgroundSize: backgroundSize,
            iconSize: iconSize,
            icons: icons,
            iconBuilder: (buttonContext) =>
                MaximizeIcon(color: buttonContext.iconColor),
            onPressed: onPressed ?? () => windowManager.maximize());
}

class RestoreWindowButton extends WindowButton {
  RestoreWindowButton(
      {Key? key,
      WindowButtonColors? colors,
      VoidCallback? onPressed,
      Size? backgroundSize,
      Size? iconSize,
      bool? animate})
      : super(
            key: key,
            colors: colors,
            backgroundSize: backgroundSize,
            iconSize: iconSize,
            animate: animate ?? false,
            iconBuilder: (buttonContext) =>
                RestoreIcon(color: buttonContext.iconColor),
            onPressed: onPressed ?? () => windowManager.maximize());
}

final _defaultCloseButtonColors = WindowButtonColors(
    mouseOver: const Color(0xFFD32F2F),
    mouseDown: const Color(0xFFB71C1C),
    iconNormal: const Color(0xFF805306),
    iconMouseOver: const Color(0xFFFFFFFF));

class CloseWindowButton extends WindowButton {
  CloseWindowButton(
      {Key? key,
      WindowButtonColors? colors,
      VoidCallback? onPressed,
      Size? backgroundSize,
      Size? iconSize,
      WindowButtonIcons? icons,
      WindowButtonBuilder? icon,
      bool? animate})
      : super(
            key: key,
            backgroundSize: backgroundSize,
            iconSize: iconSize,
            icons: icons,
            colors: colors ?? _defaultCloseButtonColors,
            animate: animate ?? false,
            iconBuilder: (buttonContext) =>
                CloseIcon(color: buttonContext.iconColor),
            onPressed: onPressed ?? () => windowManager.close());
}
